package com.csxh.web.dao.bookstore;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;

import com.csxh.util.GenericsUtil;
import com.csxh.web.dao.IDao;

public abstract class AbstractHibernateDao<T> implements IDao<T> {

	// 定义T 所对应的反射对象
	protected Class<T> clazz;

	@SuppressWarnings("unchecked")
	public AbstractHibernateDao() {
		super();
		// 所有继承该类型的对象都会调用这行代码，而this.getClass()指就是子对象的class
		// UserService userServie=new
		// UserService();this.getClass()===>userServie.getClass();
		// MenuService menuServie=new
		// MenuService();this.getClass()===>menuServie.getClass();
		this.clazz = (Class<T>) GenericsUtil.getSuperClassGenricType(this.getClass());

	}

	@Autowired
	private SessionFactory sessionFactory;

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	@Override
	public T queryOne(String hql, Object... params) {
		Session session = this.sessionFactory.getCurrentSession();
		// Session session = this.sessionFactory.openSession();
		@SuppressWarnings("rawtypes")
		Query query = session.createQuery(hql);
		int index = 0;
		for (Object param : params) {
			query.setParameter(index++, param);
		}

		@SuppressWarnings("unchecked")
		T o = (T) query.getSingleResult();

		// session.close();

		return o;
	}

	@Override
	public List<T> queryAll(String hql, Object... params) {
		Session session = this.sessionFactory.getCurrentSession();
		// Session session = this.sessionFactory.openSession();
		@SuppressWarnings("rawtypes")
		Query query = session.createQuery(hql);
		int index = 0;
		for (Object param : params) {
			query.setParameter(index++, param);
		}

		@SuppressWarnings("unchecked")
		List<T> list = (List<T>) query.getResultList();

		// session.close();

		return list;
	}

	@Override
	public <P> P queryPropertyOne(String proptyName, String condition, Object... params) {

		Session session = this.sessionFactory.getCurrentSession();
		// Session session = this.sessionFactory.openSession();
		String hql="select o."+proptyName+" from "+this.clazz.getSimpleName()+" o where "+condition;
		@SuppressWarnings("rawtypes")
		Query query = session.createQuery(hql);
		int index = 0;
		for (Object param : params) {
			query.setParameter(index++, param);
		}

		@SuppressWarnings("unchecked")
		
		P p = (P) query.setFirstResult(0).setMaxResults(1).getSingleResult();
		
		// session.close();

		return p;

	}

	@Override
	public <P> List<P> queryPropertyAll(String proptyName, String condition, Object... params) {
		
		Session session = this.sessionFactory.getCurrentSession();
		// Session session = this.sessionFactory.openSession();
		String hql="select o."+proptyName+" from "+this.clazz.getSimpleName()+" o where "+condition;
		@SuppressWarnings("rawtypes")
		Query query = session.createQuery(hql);
		int index = 0;
		for (Object param : params) {
			query.setParameter(index++, param);
		}

		@SuppressWarnings("unchecked")
		List<Object> list = (List<Object>) query.getResultList();
		List<P> pList=new ArrayList<P>(list.size());
		for(Object o : list){
			pList.add((P)o);
		}

		// session.close();

		return pList;
	}

	@Override
	public String getIdProperty() {
		// TODO Auto-generated method stub
		return "id";
	}

	@Override
	public T findOneById(Serializable id) {
		Session session = this.sessionFactory.getCurrentSession();
		// Session session = this.sessionFactory.openSession();
		T bean=session.get(this.clazz, id);
		// session.close();
		return bean;
	}

	@Override
	public T findOneByCondition(String condition, Object... params) {
		
		Session session = this.sessionFactory.getCurrentSession();
		// Session session = this.sessionFactory.openSession();

		String hql = "from " + 
		              this.clazz.getSimpleName() +
		              " o where " + 
		              condition;

		@SuppressWarnings("rawtypes")
		Query query = session.createQuery(hql);
		int index = 0;
		for (Object param : params) {
			query.setParameter(index++, param);
		}
		
		@SuppressWarnings("unchecked")
		T bean=(T)query.setFirstResult(0).setMaxResults(1).getSingleResult();
		
		// session.close();

		return bean;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> findAll() {

		// Session session = this.sessionFactory.openSession();
		Session session = this.sessionFactory.getCurrentSession();
		List<T> list = (List<T>) session.createQuery("from " + this.clazz.getSimpleName()).getResultList();
		// session.close();

		return list;
	}

	@Override
	public List<T> findAll(String orderBy) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public List<T> findAllByCondition(String condition, Object... params) {

		Session session = this.sessionFactory.getCurrentSession();
		// Session session = this.sessionFactory.openSession();

		String hql = "from " + this.clazz.getSimpleName() + " o where " + condition;

		@SuppressWarnings("rawtypes")
		Query query = session.createQuery(hql);
		int index = 0;
		for (Object param : params) {
			query.setParameter(index++, param);
		}
		@SuppressWarnings("unchecked")
		List<T> list = (List<T>) query.getResultList();

		// session.close();

		return list;
	}

	@Override
	public List<T> findAllByCondition(String orderBy, String condition, Object... params) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public long totalCount() {

		Session session = this.sessionFactory.getCurrentSession();
		// Session session = this.sessionFactory.openSession();

		String hql = "select count(o.id) from " + this.clazz.getSimpleName() + " o";
		@SuppressWarnings("rawtypes")
		Query query = session.createQuery(hql);

		long l = (Long) query.getSingleResult();

		// session.close();

		return l;
	}

	@Override
	public long totalCount(String condition, Object... params) {

		Session session = this.sessionFactory.getCurrentSession();
		// Session session = this.sessionFactory.openSession();

		String hql = "select count(o.id) from " + this.clazz.getSimpleName() + " o where " + condition;
		@SuppressWarnings("rawtypes")
		Query query = session.createQuery(hql);
		int index = 0;
		for (Object param : params) {
			query.setParameter(index++, param);
		}

		long l = (Long) query.getSingleResult();

		// session.close();

		return l;
	}

	@Override
	public boolean save(T bean) {
		Session session = this.sessionFactory.getCurrentSession();
		// Session session = this.sessionFactory.openSession();
		session.saveOrUpdate(bean);
		// session.close();
		return true;
	}

	@Override
	public boolean delete(Serializable... ids) {
		Session session = this.sessionFactory.getCurrentSession();
		// Session session = this.sessionFactory.openSession();
		for (Serializable id : ids) {

			String hql = "delete from " + this.clazz.getSimpleName() + "o where o.id=?";
			@SuppressWarnings("rawtypes")
			Query query = session.createQuery(hql);
			query.setParameter(0, id);
			int l = query.executeUpdate();
			if (l == 0) {

				throw new RuntimeException();
			}
		}
		// session.close();
		return true;
	}

	@Override
	public boolean deleteAll() {

		Session session = this.sessionFactory.getCurrentSession();
		// Session session = this.sessionFactory.openSession();

		String hql = "delete from " + this.clazz.getSimpleName();
		@SuppressWarnings("rawtypes")
		Query query = session.createQuery(hql);
		int l = query.executeUpdate();

		// session.close();

		return l > 0;
	}

	@Override
	public boolean update(T bean) {
		Session session = this.sessionFactory.getCurrentSession();
		// Session session = this.sessionFactory.openSession();

		session.merge(bean);

		// session.close();

		return true;
	}

}
